﻿// Copyright 2010 Maxime Serrano <lastchronicler@gmail.com>
using System;
using System.IO;

namespace MCSharp.Network.Handlers
{
    public class MovementHandler : PacketHandler
    {
        #region PacketHandler Members

        public void Handle(BinaryReader reader, Session session, Player player)
        {
            Position newPos = new Position();
            byte[] newArr = null;

            // Read in new position
            newPos = new Position();
            newArr = BitConverter.GetBytes(reader.ReadDouble());
            Array.Reverse(newArr);
            newPos.x = BitConverter.ToDouble(newArr, 0);

            newArr = BitConverter.GetBytes(reader.ReadDouble());
            Array.Reverse(newArr);
            newPos.y = BitConverter.ToDouble(newArr, 0);

            newArr = BitConverter.GetBytes(reader.ReadDouble());
            Array.Reverse(newArr);
            newPos.stance = BitConverter.ToDouble(newArr, 0);

            newArr = BitConverter.GetBytes(reader.ReadDouble());
            Array.Reverse(newArr);
            newPos.z = BitConverter.ToDouble(newArr, 0);

            reader.ReadBoolean();   // Unknown

            // Calculate delta
            Position delta = new Position();
            delta.x = newPos.x - player.pos.x;
            delta.y = newPos.y - player.pos.y;
            delta.z = newPos.z - player.pos.z;

            // Update player position
            player.pos.x = newPos.x;
            player.pos.y = newPos.y;
            player.pos.z = newPos.z;
            player.pos.stance = newPos.stance;

            // Check if player should relative move or teleport
            if (Math.Abs(delta.x) <= 4 &&
                Math.Abs(delta.y) <= 4 &&
                Math.Abs(delta.z) <= 4)
            {
                if (session.fullPositionUpdateCounter >= Session.fullPositionUpdateInterval)
                {
                    Server.SendToOthersInRange(PacketWriter.MakeTeleport(player), player);
                    session.fullPositionUpdateCounter = 0;
                }
                else
                {
                    Server.SendToOthersInRange(PacketWriter.MakeRelativeMove(player, delta), player);
                    session.fullPositionUpdateCounter++;
                }
            }
            else
            {
                Server.SendToOthersInRange(PacketWriter.MakeTeleport(player), player);
                session.fullPositionUpdateCounter = 0;
            }

            // Check of chunks should be loaded / unloaded
            player.UpdateChunks();
        }

        #endregion
    }

    public class MoveLookHandler : PacketHandler
    {
        #region PacketHandler Members

        public void Handle(BinaryReader reader, Session session, Player player)
        {
            Position newPos = new Position();
            byte[] newArr = null;

            // Read in new position and orientation
            newPos = new Position();
            newArr = BitConverter.GetBytes(reader.ReadDouble());
            Array.Reverse(newArr);
            newPos.x = BitConverter.ToDouble(newArr, 0);

            newArr = BitConverter.GetBytes(reader.ReadDouble());
            Array.Reverse(newArr);
            newPos.y = BitConverter.ToDouble(newArr, 0);

            newArr = BitConverter.GetBytes(reader.ReadDouble());
            Array.Reverse(newArr);
            newPos.stance = BitConverter.ToDouble(newArr, 0);

            newArr = BitConverter.GetBytes(reader.ReadDouble());
            Array.Reverse(newArr);
            newPos.z = BitConverter.ToDouble(newArr, 0);

            newArr = BitConverter.GetBytes(reader.ReadSingle());
            Array.Reverse(newArr);
            newPos.rotation = BitConverter.ToSingle(newArr, 0);

            newArr = BitConverter.GetBytes(reader.ReadSingle());
            Array.Reverse(newArr);
            newPos.pitch = BitConverter.ToSingle(newArr, 0);

            reader.ReadBoolean();   // Unknown

            // Clean the rotation and pitch
            while (newPos.rotation > 360f)
                newPos.rotation -= 360f;
            while (newPos.rotation < 0f)
                newPos.rotation += 360f;
            while (newPos.pitch > 360f)
                newPos.pitch -= 360f;
            while (newPos.pitch < 0f)
                newPos.pitch += 360f;

            // Calculate delta
            Position delta = new Position();
            delta.x = newPos.x - player.pos.x;
            delta.y = newPos.y - player.pos.y;
            delta.z = newPos.z - player.pos.z;

            // Update player's position and orientation
            player.pos.x = newPos.x;
            player.pos.y = newPos.y;
            player.pos.z = newPos.z;
            player.pos.stance = newPos.stance;
            player.pos.rotation = newPos.rotation;
            player.pos.pitch = newPos.pitch;

            Server.SendToOthersInRange(PacketWriter.MakeTeleport(player), player);                      // Only teleporting, because this packet seems to be sent on respawn

            // Check of chunks should be loaded / unloaded
            player.UpdateChunks();
        }

        #endregion
    }
}